package com.yonyou.brigade.third_parties.meiya.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.yonyou.brigade.basic_init.model.BriChannel;
import com.yonyou.brigade.basic_init.model.IChannelConfig;
import com.yonyou.brigade.basic_init.service.IBaseDocService;
import com.yonyou.brigade.basic_init.service.IUserCenterService;
import com.yonyou.brigade.third_parties.meiya.constant.MeiyaConstant;
import com.yonyou.brigade.third_parties.meiya.constant.MeiyaResultConstant;
import com.yonyou.brigade.third_parties.meiya.dao.MeiyaUserMapper;
import com.yonyou.brigade.third_parties.meiya.model.MeiyaConfig;
import com.yonyou.brigade.third_parties.meiya.model.MeiyaUser;
import com.yonyou.brigade.third_parties.meiya.model.third.*;
import com.yonyou.brigade.third_parties.meiya.service.IMeiyaPublicService;
import com.yonyou.brigade.third_parties.meiya.service.IMeiyaUserService;
import com.yonyou.brigade.third_parties.meiya.util.MeiyaUserConvertUtil;
import com.yonyou.ybzboot.starter.common.exception.BusinessException;
import com.yonyou.ybzboot.starter.common.util.RandomUtil;
import com.yonyou.ybzboot.starter.common.util.StringUtil;
import com.yonyou.ybzboot.uc.dto.UcUserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 美亚商旅公共 服务实现类
 *
 * @author kangfw5
 * @since 2019-06-11
 */
@Service
@Slf4j
public class MeiyaPublicServiceImpl extends ServiceImpl<MeiyaUserMapper, MeiyaUser> implements IMeiyaPublicService {

    private static Logger logger = LoggerFactory.getLogger(MeiyaPublicServiceImpl.class);


    @Value("${meiya.host.pc}")
    private String pcHost;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    IUserCenterService iUserCenterService;

    @Autowired
    IBaseDocService baseDocService;

    @Autowired
    IMeiyaUserService meiyaUserService;

    @Override
    public String getToken(IChannelConfig channelConfig) {
        MeiyaConfig meiyaConfig = (MeiyaConfig) channelConfig;
        String companyId = meiyaConfig.getCompanyId();
        String staffCode = meiyaConfig.getAdminStaffCode();
        String signKey = meiyaConfig.getKey();

        String passwordType = "0";
        String realName = "";
        //如果加ffff报错，或换成4位随机数
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timeStamp = sdf.format(new Date()) + RandomUtil.createNumberCode(4);

        //排序
        String[] infos = {companyId, realName, staffCode, timeStamp, signKey};
        Arrays.sort(infos, String.CASE_INSENSITIVE_ORDER);
        //拼接
        String input = String.format("%s%s%s%s%s", infos);
        String password = DigestUtils.sha1Hex(input);

        SSOParam ssoParam = new SSOParam(null, null, null, null, timeStamp, staffCode, passwordType, password, companyId, realName);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(ssoParam), headers);
        String pcBaseUrl = StringUtil.isNotEmpty(meiyaConfig.getPcBaseUrl()) ? meiyaConfig.getPcBaseUrl() : pcHost;
        String ssoResult = restTemplate.postForObject(pcBaseUrl + MeiyaConstant.PC_SSO_URI, entity, String.class);
        log.info("美亚商旅PC单点返回数据{}", ssoResult);

        return Optional.ofNullable(handleResult(ssoResult)).orElseThrow(() -> new BusinessException("单点登录获取认证失败"));
    }

    private String handleResult(String ssoResult) {
        try {
            JSONObject result = JSON.parseObject(ssoResult);
            if (MeiyaResultConstant.PC_SSO_RESULT_CODE_SUCCESS.equals(result.getString(MeiyaResultConstant.PC_SSO_RESULT_CODE))) {
                return result.getString(MeiyaResultConstant.PC_SSO_RESULT_SESSION_ID);
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }

    @Override
    public JSONObject pushApplyOrder(BriChannel channel, String tenant, String orgpk, JSONObject applyOrderJson) {
        MeiyaConfig meiyaConfig = JSON.parseObject(channel.getConfig(), MeiyaConfig.class);
        String token = this.getToken(meiyaConfig);

        JSONObject requestData = processApplyData(channel, applyOrderJson, tenant, token);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(requestData), headers);

        log.info("向美亚商旅推送申请单信息：" + JSONObject.toJSONString(entity));
        String pcBaseUrl = StringUtil.isNotEmpty(meiyaConfig.getPcBaseUrl()) ? meiyaConfig.getPcBaseUrl() : pcHost;
        String ssoResult = restTemplate.postForObject(pcBaseUrl + MeiyaConstant.SAVE_BUSINESS_APPLICATION, entity, String.class);
        log.info("向美亚商旅推送申请单信息返回数据{}", ssoResult);

        JSONObject result = new JSONObject();
        try {
            JSONObject applyResult = JSONObject.parseObject(ssoResult);
            if (MeiyaResultConstant.PC_SSO_RESULT_CODE_SUCCESS.equals(applyResult.getString(MeiyaResultConstant.PC_SSO_RESULT_CODE))) {
                String applyNum = applyResult.getString("stApplyOrderNo");
                logger.info("向美亚商旅推送申请单同步成功，返回的外部申请单号=" + applyNum);
                //返回true,ybz修改推送标记
                result.put("msg","向美亚商旅推送申请单同步成功，返回的外部申请单号=" + applyNum);
                result.put("success",true);
            }else {
                log.error("向美亚商旅推送申请单失败:" + ssoResult);
                result.put("success", false);
                result.put("msg", "向美亚商旅推送申请单失败:" + ssoResult);
            }
        }catch (Exception e){
            log.error("向美亚商旅推送申请单异常:" + e.getMessage());
            result.put("success", false);
            result.put("msg", "向美亚商旅推送申请单异常:" + e.getMessage());
            return result;
        }

        return result;
    }

    /**
     * 申请单数据处理
     *
     * @param applyOrderJson 申请单信息
     * @param tenant         租户ID
     * @param token         认证信息
     * @return {@link JSONObject}
     */
    private JSONObject processApplyData(BriChannel channel, JSONObject applyOrderJson, String tenant, String token){

        MeiyaConfig meiyaConfig = JSON.parseObject(channel.getConfig(), MeiyaConfig.class);
        String companyId = meiyaConfig.getCompanyId();
        String userId = applyOrderJson.getString("userId");

        JSONObject special = applyOrderJson.getJSONObject("special");
        String openType = special.getString("openType");

        ApplyParam applyParam = new ApplyParam();
        //制单人或出差填单人
        List<String> userIdList = new ArrayList<>();
        userIdList.add(userId);
        List<UcUserDto> users = iUserCenterService.getCompleteUcUserDtoByUserid(userIdList, tenant);
        UcUserDto sscUser = null;
        if (users != null && users.size() > 0){
            sscUser = users.get(0);
        }else {
            logger.error("未找到制单人信息：" + userId);
        }
        ApplyPassengerInfo applyPsg = getApplyPsgInfo(tenant, companyId, userId, channel);
        applyParam.setApplyPassengerInfo(applyPsg);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date startDate = applyOrderJson.getDate("startDate");
        Date endDate = applyOrderJson.getDate("endDate");
        String strBeginDate = sdf.format(startDate);
        String strEndDate = sdf.format(endDate);
        //出差开始时间:yyyy-MM-dd 【大概预算出差时间，不做具体校验，但必须传值】
        applyParam.setBeginDate(strBeginDate);
        //出差结束时间:yyyy-MM-dd【大概预算出差时间，不做具体校验，但必须传值】
        applyParam.setEndDate(strEndDate);

        //出差申请成本中心，对接默认都传null
        String assumeOrg = applyOrderJson.getString("assumeOrg");
        if (StringUtil.isNotEmpty(assumeOrg) && channel.getSyncCostInfo() != 0){
            List<CostInfo> costInfoList = new ArrayList<>();

            String[] assumeOrgArr = assumeOrg.split(",");
            switch (channel.getSyncCostInfo()){
                //传名称
                case 1:
                    if (assumeOrgArr.length > 0){
                        CostInfo costInfo = new CostInfo();
                        if (assumeOrgArr.length > 1){
                            costInfo.setCostCenterName(assumeOrgArr[1]);
                        }else {
                            Map<String, String> assumeOrgMap = baseDocService.getOrgByOsType(tenant, userId, assumeOrg, openType);
                            if (assumeOrgMap != null){
                                costInfo.setCostCenterName(assumeOrgMap.get("name"));
                            }
                        }
                        costInfoList.add(costInfo);
                    }
                    break;
                //传PK
                case 2:
                    if (assumeOrgArr.length > 0){
                        CostInfo costInfo = new CostInfo();
                        costInfo.setCostCenterName(assumeOrgArr[0]);
                        costInfoList.add(costInfo);
                    }
                    break;
                default:
                    break;
            }


            applyParam.setCostList(costInfoList);
        }
        //客户出差申请单号
        String billNum = applyOrderJson.getString("billNum");
        String applayNumber = StringUtils.isNotBlank(billNum) ? billNum : special.getString("applayNumber");
        applyParam.setOutsideOrderNo(applayNumber);
        //制单人sessiondid有效登录，出差申请单的sessiondid一定要用applyPassengerInfo里的旅客工号登录获取的sessiondid；
        applyParam.setSessionId(token);

        //实际出行人
        List<UcUserDto> companionList = new ArrayList<>();
        boolean success = getPassenger(channel, companionList, applyOrderJson, tenant, sscUser, openType);
        if (!success){
            companionList.add(sscUser);
        }

        //行程列表
        JSONObject cityCodeMap = special.getJSONObject("cityCodes");
        List<TripInfo> tripInfoList = new ArrayList<>();
        JSONArray travelList = applyOrderJson.getJSONArray("nodeBusinessTravelList");
        if (travelList != null && travelList.size() > 0){
            for (int i = 0; i < travelList.size(); i++) {
                JSONObject travel = travelList.getJSONObject(i);
                String tripWay = travel.getString("tripWay");
                String toCity = travel.getString("toCity");
                String fromCity = travel.getString("fromCity");

                TripInfo tripInfo = new TripInfo();

                if ("飞机".equals(tripWay)){
                    toCity = StringUtil.isNotEmpty(toCity) ? toCity.split("-")[0] : toCity;
                    fromCity = StringUtil.isNotEmpty(fromCity) ? fromCity.split("-")[0] : fromCity;
                    tripInfo.setIsFlight(true);
                }else {
                    tripInfo.setIsFlight(false);
                }
                if ("火车".equals(tripWay)){
                    tripInfo.setIsTrain(true);
                }else {
                    tripInfo.setIsTrain(false);
                }
                String toCityCode = cityCodeMap.getString(toCity);
                String fromCityCode = cityCodeMap.getString(fromCity);
                String airportType = travel.getString("airportType");

                tripInfo.setArrivalCity(toCity);
                tripInfo.setDepartureCity(fromCity);
                tripInfo.setStartDay(strBeginDate);
                tripInfo.setEndDay(strEndDate);
                tripInfo.setDepartureCityCode(toCityCode);
                tripInfo.setArrivalCityCode(fromCityCode);

                //出行人信息
                List<ApplyPassengerInfo> passengerInfoList = new ArrayList<>();
                for (UcUserDto ucUserDto : companionList) {
                    ApplyPassengerInfo applyPassenger = MeiyaUserConvertUtil.ucUser2ApplyPsg(tenant, companyId, ucUserDto, channel);
                    passengerInfoList.add(applyPassenger);
                }
                tripInfo.setPassengerInfoList(passengerInfoList);

                if ("飞机".equals(tripWay)){
                    if (StringUtils.isNotEmpty(fromCity) && StringUtils.isNotEmpty(toCity)) {
                        if ("I".equals(airportType)) {
                            tripInfo.setTripType(1);
                        } else {
                            tripInfo.setTripType(0);
                        }
                    }
                }

                tripInfoList.add(tripInfo);
            }
        }
        applyParam.setTripInfoList(tripInfoList);

        applyParam.setPurpose(applyOrderJson.getString("descript"));

        applyParam.setStatus(4);

        return JSONObject.parseObject(JSONObject.toJSONString(applyParam));
    }

    /**
     * 获取实际出行人信息
     * @param channel
     * @param companionList
     * @param nodeBusinessTrip
     * @param tenant
     * @param sscUser
     * @param openType
     * @return
     */
    private boolean getPassenger(BriChannel channel, List<UcUserDto> companionList, JSONObject nodeBusinessTrip, String tenant, UcUserDto sscUser, String openType) {

        MeiyaConfig meiyaConfig = JSON.parseObject(channel.getConfig(), MeiyaConfig.class);

        // 报账3.18新增市级出行人字段格式为{pk;pk}
        String actualPedestrian = nodeBusinessTrip.getString("actualPedestrian");

        // 旧的实际出行人为手输格式，支持格式  张三（17934125896），李四（14536897562）
        String companion = nodeBusinessTrip.getString("companion");

        if (org.apache.commons.lang3.StringUtils.isNotBlank(actualPedestrian)){
            actualPedestrian = convertTraveler(actualPedestrian);
            String[] split = actualPedestrian.split(";");
            List<String> personIds = new ArrayList<>();
            for (String str : split) {
                if (str.split(",").length>0){
                    personIds.add(str.split(",")[0]);
                }
            }
            List<UcUserDto> companionUser = null;
            if ("nc".equals(openType)){
                companionUser = iUserCenterService.getCompleteUcUserByPersonIds(personIds,tenant);
            }else {
                companionUser = iUserCenterService.getCompleteUcUserDtoByUserid(personIds,tenant);
            }

            if (companionUser != null && companionUser.size() == personIds.size()){

                companionList.addAll(companionUser);
            }else {
                logger.info("用户中心未找到实际出行人:" + personIds.toString());
                //TODO 用户中心未找到人员时同步erp用户，再次查找。
                throw new BusinessException("用户中心未找到部分实际出行人");
            }
        }

        if (org.apache.commons.lang3.StringUtils.isNotBlank(companion)) {
            companion = convertTraveler(companion);
            if (companion.contains(":")) {
                String[] split = companion.split(",");
                for (String str : split) {
                    String[] strings = str.split(":");
                    if (split.length == 1 && strings[0].equals(sscUser.getUserName())){
                        continue;
                    }
                    if (strings.length > 1){
                        String phoneNo = strings[1];
                        UcUserDto companionUser = iUserCenterService.getCompleteUcUserDtoByPhone(phoneNo, tenant);
                        if (companionUser != null && org.apache.commons.lang3.StringUtils.isNotEmpty(companionUser.getPersonCode())) {
                            companionList.add(companionUser);
                        } else {
                            String msg = "用户中心未找到或部分未找到实际出行人companion:" + phoneNo;
                            logger.info(msg);
                            return false;
                        }

                    }else {
                        logger.error("美亚商旅实际出行人为传手机号：" + str);
                    }
                }
            }
        }

        if(CollectionUtils.isEmpty(companionList)) {
            companionList.add(sscUser);
        }
        if (BriChannel.SYNCUSER == channel.getSyncUser()) {
            for (UcUserDto ucUserDto : companionList) {
                try {
                    Wrapper<MeiyaUser> wrapper = new EntityWrapper<>();
                    wrapper.eq(MeiyaUser.TENANT, tenant);
                    wrapper.eq(MeiyaUser.ORG, ucUserDto.getOrgPk());
                    wrapper.eq(MeiyaUser.USER_ID, ucUserDto.getUserId());
                    List<MeiyaUser> meiYaUsers = meiyaUserService.selectList(wrapper);
                    if (CollectionUtils.isEmpty(meiYaUsers)){
                        MeiyaUser ucMeiyaUser = MeiyaUserConvertUtil.ucUser2Meiya(tenant, meiyaConfig.getCompanyId(), ucUserDto);
                        meiyaUserService.syncUsers(meiyaConfig, Collections.singletonList(ucMeiyaUser), channel);
                    }
                }catch (Exception e){
                    logger.error("同步美亚申请单同步人员异常：" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 转换companion中的字符
     *
     * @param companion
     * @return
     */
    public static String convertTraveler(String companion) {
        String convertStr = companion;
        if (companion.contains("（")) {
            convertStr = companion.replaceAll("（", ":");
        }
        if (companion.contains("(")) {
            convertStr = convertStr.replaceAll("\\(", ":");
        }
        if (companion.contains("）")) {
            convertStr = convertStr.replaceAll("）", "");
        }
        if (companion.contains(")")) {
            convertStr = convertStr.replaceAll("\\)", "");
        }
        if (companion.contains("，")) {
            convertStr = convertStr.replaceAll("，", ",");
        }
        if (companion.contains("、")) {
            convertStr = convertStr.replaceAll("、", ",");
        }
        return convertStr;
    }

    private ApplyPassengerInfo getApplyPsgInfo(String tenant, String companyId, String userId, BriChannel briChannel) {
        List<String> userIdList = new ArrayList<>();
        userIdList.add(userId);
        List<UcUserDto> users = iUserCenterService.getCompleteUcUserDtoByUserid(userIdList, tenant);
        if (users.size() > 0) {
            return MeiyaUserConvertUtil.ucUser2ApplyPsg(tenant, companyId, users.get(0), briChannel);
        }else {
            return null;
        }
    }
}
